import { isObject } from "../utils";
import { arrayMethods } from "./array";
import { Dep } from './dep'
// 检测数据变化  类有类型  知道是谁的实例
class Observe {
  constructor(data) {//对对象中所有属性进行劫持
    Object.defineProperty(data, '__ob__', {
      value: this,
      enumerable: false
    })
    // 因为有可能是是数组  是数组就不劫持了 性能开支太大了

    if (Array.isArray(data)) {
      // 数组劫持的逻辑
      // 对数组方法重写  切片编程   高阶函数
      data.__proto__ = arrayMethods
      // 处理数组当中是对象或者数组的劫持逻辑
      this.observeArray(data)

    } else {
      // 对象数据劫持
      this.walk(data)
    }

  }
  observeArray (data) {
    data.forEach(item => {
      observe(item)
    })
  }


  walk (data) {
    //不会遍历原型链 值遍历对象自身私有的属性
    Object.keys(data).forEach((key) => {
      defineReactive(data, key, data[key])
    })
  }
}
// vue2会对对象进行遍历 用defineProperty 让当中的每个数据变成响应式  导致性能不高
function defineReactive (data, key, value) {
  // value 有可能是对象  递归
  observe(value)
  let dep = new Dep()//给每个属性都添加一个dep
  Object.defineProperty(data, key, {
    get () {
      // 取值 让watcher和dep关联
      if (Dep.target) {
        // 此值是再模板中使用的
        dep.depend() //让dep记住watcher
      }
      return value
    },
    set (newVal) {
      // 用户赋值一个对象
      if (newVal !== value) {
        observe(newVal)
        value = newVal
        dep.notify()//告诉当前属性存放的watcher执行
      }

    }
  })
}
export function observe (data) {
  // 如果是对象才观测、
  if (isObject(data)) {
    return;
  }
  if (data.__ob__) {
    return
  }
  // 默认最外层的data是对象
  return new Observe(data)
}